<?php

namespace wxpay;


use app\common\model\Wx_Pay_Record;

include_once 'lib/WxPay.Api.php';

/**
 * 微信支付
 * @author hy
 */
class WxPay
{
    /**
     * @return static|self
     */
    public static function instance()
    {
        static $ob;
        if (empty($ob)) {
            PayConfig::init();
            $ob = new self();
        }
        return $ob;
    }

    /**
     * 用户扫描二维码支付
     * @param array $param [
     *                  body         必填   商品描述
     *                order_sn     必填   订单号
     *                total_fee    必填   支付金额
     *                product_id   必填   商品id
     *                ]
     * @param string $orderType 订单类型  订单支付成功通知根据类型做处理  暂时为default
     * @return array 二维码内容
     */
    public function native($param, $orderType = 'default')
    {
        if (empty($param['product_id'])) {
            return error('商品id不能为空');
        }
        $record = new Wx_Pay_Record();
        $order = $record->getRecordByOrderSn($param['order_sn']);
        if ($order) {
            if ($order['pay_paid'] == 1) {
                return error('订单已支付');
            }
            if (time() - $order['pay_created_date'] < 1200 && $order['pay_paid_amount'] == $param['total_fee']) {
                return success($order['code_url']);
            }
        }

        $result = self::WxPayUnifiedOrder($param, $orderType);
        if ($result['errCode']) {
            return error($result['message']);
        }
        $result = $result['data'];

        if ($result['return_code'] == 'SUCCESS') {
            if ($result['result_code'] == 'FAIL') {
                return error($result['err_code_des']);
            }
            return success($result['code_url']);
        }
        return error('二维码创建失败');
    }
    

    /**
     * 获取js支付参数
     * @param array $param [
     *                  body         必填   商品描述
     *                order_sn     必填   订单号
     *                total_fee    必填   支付金额 分
     *                openid       必填   用户openid
     *                ]
     * @param string $orderType 订单类型  订单支付成功通知根据类型做处理  暂时为default
     */
    public function jspayParams($param, $orderType = 'default')
    {
        if (empty($param['openid'])) {
            return error('用户openid不能为空');
        }
        $record = new Wx_Pay_Record();
        $order = $record->getRecordByOrderSn($param['order_sn']);

        if ($order && $order['pay_paid'] == 1) {
            return error('订单已支付');
        } elseif ($order && (NOW_TIME - strtotime($order['create_time']) < 1200)) {
            $prepay_id = $order['prepay_id'];
        } else {
            $param['trade_type'] = 'JSAPI';

            $result = self::WxPayUnifiedOrder($param, $orderType);

            if ($result['errCode']) {
                return error($result['message']);
            }
            $result = $result['data'];
            $prepay_id = $result['prepay_id'];
        }

        $jsApi = new \WxPayJsApiPay();
        $jsApi->SetAppid(PayConfig::$AppId);
        $jsApi->SetTimeStamp((string)time());
        $jsApi->SetNonceStr(\WxPayApi::getNonceStr());
        $jsApi->SetPackage("prepay_id=" . $prepay_id);
        $jsApi->SetSignType("MD5");
        $jsApi->SetPaySign($jsApi->MakeSign());
        $parameters = json_encode($jsApi->GetValues());
        return success($parameters);
    }

    /**
     * 微信支付订单的查询
     * @param string $orderSn 订单号
     */
    public static function orderQuery($orderSn)
    {
        $input = new \WxPayOrderQuery();
        $input->SetOut_trade_no($orderSn);
        $result = \WxPayApi::orderQuery($input);
        if ($result['return_code'] == 'SUCCESS') {
            if ($result['result_code'] == 'FAIL') {
                return error($result['err_code_des'], 1, $result);
            }
            if ($result['trade_type'] != 'SUCCESS') {
                return error($result['trade_state_desc'], 1, $result);
            }
            return success($result);
        }
        return error('订单查询失败');
    }


    /**
     * 退款
     * @param string $orderSn 订单号
     * @param int $refundFee 退款金额 (分)
     * @param string $refundSn 自定义退款订单号
     */
    public function refund($orderSn, $refundFee, $refundSn = '')
    {
        $order = Wx_Pay_Record::instance()->getRecordByOrderSn($orderSn);
        if (empty($order) || $order['pay_paid'] == 0) {
            return error('订单不存在，或未支付');
        }
        if (($order['pay_paid_amount'] - $order['refund_fee']) < $refundFee) {
            return error('退款失败，退款金额大于支付金额');
        }
        $input = new \WxPayRefund();
        $input->SetTransaction_id($order['pay_transid']);
        $input->SetTotal_fee($order['pay_paid_amount']);
        $input->SetRefund_fee($refundFee);
        $input->SetOut_refund_no(empty($refundSn) ? ('refund' . $orderSn) : $refundSn);
        $input->SetOp_user_id(PayConfig::$MchId);
        $result = \WxPayApi::refund($input);
        if ($result['return_code'] == 'SUCCESS') {
            if (!empty($result['err_code'])) {
                return error($result['err_code_des']);
            }
            $update = [
                'pay_id' => $order['pay_id'],
                'refund_fee' => empty($order['refund_fee']) ? $result['refund_fee'] : $order['refund_fee'] + $result['refund_fee'],
                'refund_order_sn' => $result['refund_id'],
            ];

            if ($update['refund_fee'] > $order['pay_paid_amount']) {
                $update['refund_fee'] = $order['pay_paid_amount'];
            }

            $rel = Wx_Pay_Record::instance()->saveRecord($update);
            if ($rel === false || !empty($rel['errCode'])) {
                return error('更新退款信息失败');
            }
            return success($result);
        }
        return error('退款失败');
    }


    /**
     * 生成统一下单
     * @param array $param [
     *                body         必填   商品描述
     *                order_sn     必填   订单号
     *                total_fee    必填   支付金额 (分)
     *                product_id    -   交易类型为 NATIVE 时必传
     *                openid        -   交易类型为 JSAPI 时必传
     *                notify_url        订单成功通知地址
     *                trade_type        交易类型 JSAPI NATIVE APP
     *                attach            附加数据
     *                expire_time       订单过期时间
     *                detail            商品详情
     *                goods_tag         商品标记
     *              ]
     */
    public function WxPayUnifiedOrder($param, $orderType)
    {
        if (empty($param['body']) || empty($param['order_sn']) || empty($param['total_fee'])) {
            return error('参数错误请检查');
        }
        $out_trade_num = $param['order_sn'] . rand(1000, 9999);
        $input = new \WxPayUnifiedOrder();
        $input->SetBody($param['body']);
        $input->SetOut_trade_no($out_trade_num);
        $input->SetTotal_fee($param['total_fee']);
        $input->SetNotify_url($param['notify_url']);   //订单通知地址
        $input->SetTrade_type(empty($param['trade_type']) ? 'NATIVE' : $param['trade_type']);//交易类型 JSAPI NATIVE APP
        $input->SetTime_start(date('YmdHis'));
        $input->SetTime_expire(empty($param['expire_time']) ? date('YmdHis', time() + 1200) : $param['expire_time']);//订单失效时间 20分钟
        $input->SetAttach(empty($param['attach']) ? '' : $param['attach']);
        $input->SetDetail(empty($param['detail']) ? '' : $param['detail']);
        $input->SetGoods_tag(empty($param['goods_tag']) ? '' : $param['goods_tag']);   //商品标记
        $input->SetProduct_id(empty($param['product_id']) ? '' : $param['product_id']);  //商品id
        $input->SetOpenid(empty($param['openid']) ? '' : $param['openid']);      //jsapi时必传

        $result = \WxPayApi::unifiedOrder($input);
        if ($result['return_code'] != 'SUCCESS') {
            return error($result['return_msg']);
        }
        if (isset($result['err_code'])) {
            return error($result['err_code_des']);
        }

        //保存支付订单
        $data = [
            'pay_out_trade_num' => $out_trade_num,
            'pay_order_sn' => $param['order_sn'],
            'pay_order_type' => $orderType,
            'pay_order_product_name' => $param['body'],
            'pay_paid' => 0,
            'pay_summary' => $param['body'],
            'pay_modified_date' => time(),
            'prepay_id' => empty($result['prepay_id']) ? '' : $result['prepay_id'],
            'code_url' => empty($result['code_url']) ? '' : $result['code_url'],
        ];
        $record = new Wx_Pay_Record();
        $rel = $record->saveRecord($data);
        if ($rel == false && isset($rel['errCode'])) {
            return error('订单保存失败');
        }

        return success($result);
    }


    public function sign($data)
    {
        $ob = new \WxPayResults();
        foreach ($data as $k => $v) {
            $ob->SetData($k, $v);
        }
        return $ob->MakeSign();
    }


}